use cmsis_rtos2_rs::static_mem::{MsgQueue, Task, Thread};
use utils::MutCell;

use crate::app::{self, proto::{self, poll_ack, EmptyResponse, Request, RequestRef}, service::dispatcher::send_to_ipc_res};

struct HandlerTask;

struct Context {
    thread: Thread<2048>,
    mq: MsgQueue<Request, 5>,
    run_flag: MutCell<u8>,
}

impl Context {
    const fn uninit() -> Self {
        Self {
            thread: Thread::uninit(),
            mq: MsgQueue::uninit(),
            run_flag: MutCell::const_new(poll_ack::FINISH),
        }
    }

    unsafe fn init_once(&self) {
        self.mq.init_once();
        self.thread.spawn(&HandlerTask);
    }

    fn set_run_flag(&self, flag: u8) {
        unsafe {
            self.run_flag.as_mut_ptr().write_volatile(flag);
        }
    }
}

static CTX: Context = Context::uninit();

impl Task for HandlerTask {
    fn run(&self) {
        loop {
            CTX.set_run_flag(poll_ack::FINISH);

            let request = CTX.mq.poll(100);

            if let Some(request) = request {
                CTX.set_run_flag(poll_ack::RUN);
                let req_ref = request.as_ref();
                dispatch(req_ref);
            } else {
                run_idle();
            }

        }
    }
}

pub fn post_request(req: Request) {
    _ = CTX.mq.post(req);
}

pub fn get_run_flag() -> u8 {
    unsafe { CTX.run_flag.as_mut_ptr().read_volatile() }
}

pub unsafe fn start() {
    CTX.init_once();
}

fn run_idle() {

    #[cfg(feature = "cp_cargo")]
    app::cargo::exec::on_idle();
}   

fn dispatch(req: RequestRef) {

    #[cfg(feature = "cp_drop")]
    let ret = app::drop::exec::on_request(&req);

    #[cfg(feature = "cp_cargo")]
    {
        if proto::cmd::cargo::SCAN == req.cmd_or_other() {
            app::cargo::exec::on_scan(&req);
            return;
        }
    }

    #[cfg(feature = "cp_cargo")]
    let ret = app::cargo::exec::on_request(&req);
    send_to_ipc_res(&EmptyResponse::new(&req, &ret));
}












